#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

from abc import ABC, abstractmethod

from common.const import RepositoryDataTypeEnum
from informix.comm.comm import check_path_legal
from informix.comm.const import JsonConstant, FileConstant, MountType
from informix.job_manager import JobManager


class BaseParam(ABC):
    # 该类定义为抽象基类，不能直接实例化
    def __init__(self, json_param, job_manager: JobManager, log_obj):
        self._json_param = json_param
        self._log_obj = log_obj
        self._pid = job_manager.pid
        self._job_id = job_manager.job_id
        self._sub_job_id = job_manager.sub_job_id
        self._mount_type = self._json_param.get(JsonConstant.JOB, {}).get(JsonConstant.EXTEND_INFO, {}) \
            .get(JsonConstant.AGENT_MOUNT_TYPE, '')
        if not self._json_param:
            raise Exception(f"json param is null.")

    def get_log_common(self):
        key_list = ["pid", "jobId", "subjobId"]
        value_list = [self._pid, self._job_id, self._sub_job_id]
        k_v_tuples = zip(key_list, value_list)
        return " ".join([f"{k}:{v}" for k, v in k_v_tuples if v])

    def get_copy(self):
        """
        获取job -> copy
        :return: list
        """
        return self._json_param.get(JsonConstant.JOB, {}).get(JsonConstant.COPY, [])

    def get_copy_key(self, copy_index: int, key: str):
        """
        获取指定索引的副本信息中的指定字段 job -> copy[copy_index] -> key
        :param copy_index: 副本索引
        :param key: 待获取的字段名称
        """
        if not self._json_param:
            self._log_obj.error(f"Json param is null. {self.get_log_common()}")
            return ""
        copy = self._json_param.get(JsonConstant.JOB, {}).get(JsonConstant.COPY, [])
        if not copy:
            self._log_obj.error(f"Copy is null. {self.get_log_common()}")
            return ""
        copy_status1 = (copy_index < 0 and len(copy) < -copy_index)
        copy_status2 = (copy_index > 0 and len(copy) < copy_index + 1)
        if copy_status1 or copy_status2:
            self._log_obj.error(f"The copy_index is out of range. number of copies:{len(copy)}")
            return ''
        value = copy[copy_index].get(key)
        if not value:
            self._log_obj.error(f"Get value id failed. {self.get_log_common()}")
        return value

    def get_copy_id(self, copy_index: int = -1):
        """
        获取 获取指定索引的副本信息中的id字段 job -> copy[copy_index] -> id
        :param copy_index: 副本索引默认取-1
        :return: str
        """
        return self.get_copy_key(copy_index, JsonConstant.ID)

    def get_job_protectenv(self):
        """
         获取 job -> protectEnv
        :return: dict
        """
        return self._json_param.get(JsonConstant.JOB, {}).get(JsonConstant.PROTECT_ENV, {})

    def get_job_protectobject(self):
        """
        获取 job -> protectObject
        :return: dict
        """
        return self._json_param.get(JsonConstant.JOB, {}).get(JsonConstant.PROTECT_OBJECT, {})

    @abstractmethod
    def get_job_repositories(self):
        # 抽象方法子类必须实现
        pass

    def get_designated_path_ex(self, rep_type, repositories: list):
        if not repositories:
            self._log_obj.error(f"Repositories is null. rep_type:{rep_type} {self.get_log_common()}")
            return ""
        for repository in repositories:
            if repository.get(JsonConstant.REPOSITORY_TYPE, "") != rep_type:
                continue
            path_array = repository.get(JsonConstant.PATH, [])
            self._log_obj.info(f"Get Path array: {path_array}")
            if len(path_array) <= 0 or not path_array[0]:
                continue
            # 返回取到得路径中的第一个符合合法性校验的
            for path in path_array:
                if check_path_legal(path, FileConstant.INFORMIX_FILESYSTEM_MOUNT_PATH):
                    return path
        return ""

    def get_designated_path_ex_list(self, rep_type, repositories: list):
        ret = []
        if not repositories:
            self._log_obj.error(f"Repositories is null. rep_type:{rep_type} {self.get_log_common()}")
            return []
        for repository in repositories:
            if repository.get(JsonConstant.REPOSITORY_TYPE, "") != rep_type:
                continue
            path_array = repository.get(JsonConstant.PATH, [])
            if len(path_array) <= 0 or not path_array[0]:
                continue
            for path in path_array:
                if check_path_legal(path, FileConstant.INFORMIX_FILESYSTEM_MOUNT_PATH):
                    ret.append(path)
        return ret

    def get_designated_path(self, rep_type):
        repositories = self.get_job_repositories()
        return self.get_designated_path_ex(rep_type, repositories)

    def get_cache_path(self):
        return self.get_designated_path(RepositoryDataTypeEnum.CACHE_REPOSITORY.value)

    def get_data_path(self):
        return self.get_designated_path(RepositoryDataTypeEnum.DATA_REPOSITORY.value)

    def get_meta_path(self):
        repositories = self.get_job_repositories()
        if not repositories:
            return ""
        for repository in repositories:
            if repository.get(JsonConstant.REPOSITORY_TYPE, "") != RepositoryDataTypeEnum.META_REPOSITORY.value:
                continue
            path_array = repository.get(JsonConstant.PATH, [])
            if len(path_array) <= 0 or not path_array[0]:
                continue
            # 本地盘环境直接返回第一个合法路径
            if self._mount_type == MountType.FUSE:
                if check_path_legal(path_array[0], FileConstant.INFORMIX_FILESYSTEM_MOUNT_PATH):
                    self._log_obj.info(f"META PATH:{path_array[0]} {self.get_log_common()}")
                    return path_array[0]
            # 返回取到得路径中的第一个符合合法性校验的
            for path in path_array:
                if "/meta/" not in path:
                    continue
                if check_path_legal(path, FileConstant.INFORMIX_FILESYSTEM_MOUNT_PATH):
                    self._log_obj.info(f"META PATH:{path} {self.get_log_common()}")
                    return path
        return ""

    def get_subjob(self):
        """
        获取 subJob
        :return: dict
        """
        return self._json_param.get(JsonConstant.SUB_JOB, {})

    def get_subjob_key(self, key: str):
        """
        获取 subJob -> key
        :return: str
        """
        value = self._json_param.get(JsonConstant.SUB_JOB, {}).get(key)
        return value

    def get_subjob_jobname(self):
        """
        获取 subJob -> jobName
        :return:str
        """
        return self.get_subjob_key(JsonConstant.JOB_NAME)
